﻿using UnityEditor;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;

namespace GameToolkit.Editor
{
    public class FlowEdge : Edge
    {
        VisualElement mFlowPointer;

        float _totalEdgeLength;
        float _passedEdgeLength;
        int _flowPhaseIndex;
        float _currentPhaseLength;
        double _flowPhaseStartTime;
        double _flowPahseDuration;

        float mFlowSize = 10f;
        float mFlowSpeed;
        public float speed
        {
            get { return mFlowSpeed; }
            set
            {
                if (!Mathf.Approximately(mFlowSpeed, value))
                {
                    var wasEnable = speed > 0;
                    mFlowSpeed = value;
                    var isEnable = value > 0;
                    if (wasEnable != isEnable)
                    {
                        if (isEnable)
                        {
                            Add(mFlowPointer);
                        }
                        else
                        {
                            Remove(mFlowPointer);
                        }
                    }
                }
            }
        }

        public float FlowPointerSize
        {
            get { return mFlowSize; }
            set
            {
                if (!Mathf.Approximately(mFlowSize, value))
                {
                    mFlowSize = value;
                    mFlowPointer.style.width = new Length(mFlowSize, LengthUnit.Pixel);
                    mFlowPointer.style.height = new Length(mFlowSize, LengthUnit.Pixel);
                }
            }
        }

        public FlowEdge() : base()
        {
            viewDataKey = GUID.Generate().ToString();
            AddToClassList("flow-edge");
            mFlowPointer = new VisualElement(); 
            mFlowPointer.name = "FlowEdgePointer";
            mFlowPointer.style.width = new Length(mFlowSize, LengthUnit.Pixel);
            mFlowPointer.style.height = new Length(mFlowSize, LengthUnit.Pixel);

            edgeControl.RegisterCallback<GeometryChangedEvent>(OnBuildGeometryEvent);

            var sheet = BehaviourTreeGraphUtils.GetStyleSheet();
            if (sheet != null)
                styleSheets.Add(sheet);
            //StyleSheet styleSheet = Panel.LoadResource(sheetPath, typeof(StyleSheet), scaledPixelsPerPoint) as StyleSheet;
            //if (styleSheet == null)
            //{
            //    if (!s_InternalStyleSheetPath.IsMatch(sheetPath))
            //    {
            //        Debug.LogWarning($"Style sheet not found for path \"{sheetPath}\"");
            //    }
            //}
            //else
            //{
            //    styleSheets.Add(styleSheet);
            //}
            //speed = 120;
        }

        public override bool UpdateEdgeControl()
        {
            var upd = base.UpdateEdgeControl();
            if (upd)
                UpdateFlow();
            return upd;
        }

        private void OnBuildGeometryEvent(GeometryChangedEvent evt)
        {
            if (mFlowSpeed > 0)
            {
                var ctrlPoints = edgeControl.controlPoints;
                _flowPhaseIndex = 0;
                _passedEdgeLength = 0;
                _flowPhaseStartTime = EditorApplication.timeSinceStartup;
                _currentPhaseLength = Vector2.Distance(ctrlPoints[_flowPhaseIndex], ctrlPoints[_flowPhaseIndex + 1]);
                _flowPahseDuration = _currentPhaseLength / mFlowSpeed;

                _totalEdgeLength = 0;
                for (int i = 1; i < ctrlPoints.Length; i++)
                {
                    var p1 = ctrlPoints[i - 1];
                    var p2 = ctrlPoints[i];
                    _totalEdgeLength += Vector2.Distance(p1, p2);
                }
            }
        }

        void UpdateFlow()
        {
            if (mFlowSpeed > 0)
            {
                var progress = (EditorApplication.timeSinceStartup - _flowPhaseStartTime) / _flowPahseDuration;
                var startPoint = edgeControl.controlPoints[_flowPhaseIndex];
                var endPoint = edgeControl.controlPoints[_flowPhaseIndex + 1];
                var pos = Vector2.Lerp(startPoint, endPoint, (float)progress);
                mFlowPointer.transform.position = pos - new Vector2(mFlowSize, mFlowSize) * 0.5f;

                var colpro = (_passedEdgeLength + _currentPhaseLength * progress) / _totalEdgeLength;
                var color0 = edgeControl.outputColor;
                var color1 = edgeControl.inputColor;
                var col = Color.Lerp(color0, color1, (float)colpro);
                mFlowPointer.style.backgroundColor = col;

                if (progress >= 0.9999f)
                {
                    _passedEdgeLength += _currentPhaseLength;
                    _flowPhaseIndex++;
                    if (_flowPhaseIndex >= edgeControl.controlPoints.Length - 1)
                    {
                        _flowPhaseIndex = 0;
                        _passedEdgeLength = 0;
                    }
                    _flowPhaseStartTime = EditorApplication.timeSinceStartup;
                    _currentPhaseLength = Vector2.Distance(edgeControl.controlPoints[_flowPhaseIndex],
                        edgeControl.controlPoints[_flowPhaseIndex + 1]);
                    _flowPahseDuration = _currentPhaseLength / mFlowSpeed;
                }
            }
        }
    }


    public class LinkEdge : Edge
    {

        public LinkEdge() : base()
        {
            viewDataKey = GUID.Generate().ToString();
            AddToClassList("link-edge");
            var sheet = BehaviourTreeGraphUtils.GetStyleSheet();
            if (sheet != null)
                styleSheets.Add(sheet);
        }

    }
}
